%include "pm.inc"

org 	07c00h
	jmp 	LABEL_BEGIN
;----------------------------------------------------------------------
[section .gdt]
LABEL_GDT:			Descriptor 		0,0,0							;空描述符
LABEL_DESC_NORMAL:	Descriptor 		0,0ffffh,DA_DRW					;Normal描述符
LABEL_DESC_CODE32: 	Descriptor 		0,SegCode32Len-1,DA_C+DA_32		;非一致代码段,32
LABEL_DESC_CODE16:	Descriptor 		0,0ffffh,DA_C					;非一致代码段,16
LABEL_DESC_DATA:	Descriptor		0,DataLen-1,DA_DRW				;Data
LABEL_DESC_STACK:	Descriptor 		0,TopOfStack,DA_DRWA+DA_32		;Stack,32
LABEL_DESC_TEST:	Descriptor 		0500000h,0ffffh,DA_DRW			;用于测试的描述符
LABEL_DESC_VIDEO:	Descriptor 		0b8000h,0ffffh,DA_DRW	;显存首地址
;-----------------------------------------------------------------------------
GdtLen		equ 	$-LABEL_GDT		;gdt长度
GdtPtr		equ 	GdtLen-1		;GDT界限
			dd		0				;GDT基址
;-------------------------------------------------------------------------			
;GDT选择子
SelectorNormal		equ 	LABEL_DESC_NORMAL-LABEL_GDT
SelectorCode32 		equ		LABEL_DESC_CODE32-LABEL_GDT
SelectorCode16 		equ		LABEL_DESC_CODE16-LABEL_GDT
SelectorData 		equ 	LABEL_DESC_DATA-LABEL_GDT
SelectorStack 		equ 	LABEL_DESC_STACK-LABEL_GDT
SelectorTest		equ 	LABEL_DESC_TEST-LABEL_GDT
selectorVideo		equ		LABEL_DESC_VIDEO-LABEL_GDT
;-----------------------------------------------------------------------------

[section .data1]								;数据段
align		32
[bits 32]
LABEL_DATA:
SPValueInRealMode	dw 		0
PMMessage:			db		"In protect model now",0
OffsetPMMessage 	equ 	PMMessage-$$
StrTest:			db		"ABCDEFGHIJKLMNOPQRSTUVWXYZ",0
OffsetStrTest		equ 	StrTest-$$
DataLen				equ 	$-LABEL_DATA
;-----------------------------------------------------------------------
;全局堆栈段
[section .gs]
align		32
[bits 32]
LABEL_STACK:
	times 512 db 0
TopOfStack 			equ 	$-LABEL_STACK-1

;--------------------------------------------------------------------------
[section .s16]									;实模式向保护模式跳转
[bits 16]
LABEL_BEGIN:
	mov 	ax,cs								;把所有段寄存器都指向代码段
	mov 	ds,ax
	mov 	es,ax
	mov 	ss,ax
	mov 	sp,0100h
	
	mov 	[LABEL_GO_BACK_TO_REAL+3],ax
	mov 	[SPValueInRealMode],sp
	
	;初始化16位代码段
	xor 	eax,eax		;eax清零
	mov 	ax,cs
	shl 	eax,4
	add 	eax,LABEL_SEG_CODE16
	mov 	word[LABEL_DESC_CODE16+2],ax		;设定s32的GDT的内容
	shr		eax,16
	mov 	byte[LABEL_DESC_CODE16+4],al
	mov 	byte[LABEL_DESC_CODE16+7],ah
	
	;初始化32位代码段描述符						让其指向LABEL_SEG_CODE32
	xor 	eax,eax		;eax清零
	mov 	ax,cs
	shl 	eax,4
	add 	eax,LABEL_SEG_CODE32
	mov 	word[LABEL_DESC_CODE32+2],ax		;设定s32的GDT的内容
	shr		eax,16
	mov 	byte[LABEL_DESC_CODE32+4],al
	mov 	byte[LABEL_DESC_CODE32+7],ah
	
	;初始化数据段描述符
	xor 	eax,eax		;eax清零
	mov 	ax,cs
	shl 	eax,4
	add 	eax,LABEL_DATA
	mov 	word[LABEL_DESC_DATA+2],ax		;设定s32的GDT的内容
	shr		eax,16
	mov 	byte[LABEL_DESC_DATA+4],al
	mov 	byte[LABEL_DESC_DATA+7],ah
	
	;初始化堆栈段描述符
	xor 	eax,eax		;eax清零
	mov 	ax,cs
	shl 	eax,4
	add 	eax,LABEL_STACK
	mov 	word[LABEL_DESC_STACK+2],ax		;设定s32的GDT的内容
	shr		eax,16
	mov 	byte[LABEL_DESC_STACK+4],al
	mov 	byte[LABEL_DESC_STACK+7],ah
	
	;为加载GDTR作准备GDTR(48位)=32位基地址+16位界限
	xor 	eax,eax
	mov 	ax,ds								
	shl 	eax,4
	add 	eax,LABEL_GDT
	mov 	dword[GdtPtr+2],eax					;让GdtPtr的GDT指向LABEL_GDT
	
	;加载GDTR
	lgdt 	[GdtPtr]
	
	cli		;关中断
	
	;打开A20
	in 		al,92h
	or 		al,00000010b
	out 	92h,al
	
	;准备切换到保护模式
	mov 	eax,cr0
	or 		eax,1
	mov		cr0,eax
	
	;进入保护模式
	jmp		dword SelectorCode32:0			;把SelectorCode32装入cs,并跳转到SelectorCode32:0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LABEL_REAL_ENTRY:							;从保护模式跳到实模式就到了这里
	mov 	ax,cs
	mov 	ds,ax
	mov 	es,ax
	mov 	ss,ax
	
	mov 	sp,[SPValueInRealMode]
	
	in 		al,92h
	and 	al,11111101b
	out 	92h,al
	
	sti										;开中断
	
	mov		ax,4c00h
	int 	21h
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;--------------------------------------------------------------------------------------
[section .s32]
[bits 32]
LABEL_SEG_CODE32:
	mov 	ax,SelectorData
	mov 	ds,ax
	
	mov 	ax,SelectorTest
	mov 	es,ax
	
	mov 	ax,SelectorStack 
	mov 	ss,ax
	mov 	esp,TopOfStack

	mov 	ax,selectorVideo
	mov 	gs,ax
	
	;显示一个字符串
	mov 	ah,0ch							;0000黑底	1100:红字
	xor 	esi,esi
	xor 	edi,edi
	mov 	esi,OffsetPMMessage
	mov		edi,(80*10+0)*2
	cld
.1:
	lodsb
	test 	al,al
	jz 		.2
	mov 	[gs:edi],ax
	add 	edi,2
	jmp		.1
.2:			;显示完毕
	call	 DispReturn
	
	call 	TestRead
	call 	TestWrite
	call 	TestRead
	
	jmp 	SelectorCode16:0
;--------------------------------------------------
TestRead:
	xor 	esi,esi
	mov 	ecx,8
.loop:
	mov 	al,[es:esi]
	call	DispAL
	inc 	esi
	loop	.loop
	
	call	DispReturn
	
	ret
;-----------------------------------------
TestWrite:
	push 	esi
	push 	edi
	xor 	esi,esi
	xor 	edi,edi
	mov 	esi,OffsetStrTest
	cld
.1:
	lodsb
	test 	al,al
	jz		.2
	mov 	[es:edi],al
	inc 	edi
	jmp 	.1
.2:
	pop		edi
	pop		esi
	
	ret
;--------------------------------------
DispAL:
	push 	ecx
	push 	edx
	
	mov 	ah,0ch
	mov 	dl,al
	shr		al,4	
	mov 	ecx,2
.begin:
	and 	al,01111b
	cmp		al,9
	ja 		.1
	add 	al,'0'
	jmp		.2		
.1:
	sub 	al,0ah
	add 	al,'A'
.2:
	mov 	[gs:edi],ax
	add 	edi,2
	
	mov 	al,dl
	loop 	.begin
	add 	edi,2
	
	pop		edx
	pop		ecx
	ret
;-----------------------------------
DispReturn:
	push 	eax
	push 	ebx
	mov 	eax,edi
	mov 	bl,160
	div 	bl
	and 	eax,0ffh
	inc 	eax
	mov 	bl,160
	mul 	bl
	mov 	edi,eax
	pop 	ebx
	pop	 	eax
	
	ret
;----------------------------------

SegCode32Len 	equ 	$-LABEL_SEG_CODE32
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
[section .s16code]					;保护模式跳回实模式
align 	32
[bits 16]
LABEL_SEG_CODE16:
	mov		ax,SelectorNormal
	mov 	ds,ax
	mov 	es,ax
	mov 	fs,ax
	mov 	gs,ax
	mov 	ss,ax
	
	mov 	eax,cr0
	and 	al,11111110b			;把最后一位变成0
	mov 	cr0,eax
	
LABEL_GO_BACK_TO_REAL:
	jmp		0:LABEL_REAL_ENTRY

Code16Len	equ 	$-LABEL_SEG_CODE16
;--------------------------------------------------------------------------------
